﻿#pragma once

#include <QObject>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QList>
#include "utility.h"
#include <cassert>
#include "debug.h"
#include "netdef.h"

#include "osapi/Socket.h"

#define TEM_BUFFER_SIZE 2048
#define TCP_PKT_HERDER_SIZE 2

class TcpPkt
{
public:
	int buf_len;
	uint8_t  header[TCP_PKT_HERDER_SIZE];
	char * buf;

	TcpPkt(uint16_t buf_size,uint16_t pkt_type, char *buffer) 
	{
		buf_len = buf_size+2; 
		Utility::ilittle_to_big_endian_16(header,buf_size+2); 
		this->buf = new char[buf_size + 2];
		Debug("pkt_type : %d",pkt_type);
		memcpy(this->buf,(char *) &pkt_type, 2);

		/*uint16_t t;
		memcpy(&t, buf, 2);
		Debug(" t : %d",t);*/

		memcpy(this->buf+2,buffer,buf_size);
	}
	~TcpPkt() {}
};

#include "Utility.h"


struct message
{
	char *buffer;
	int  size;
};

/*
将接到的数据流  分成标准的数据包  

注意：
   1. 添加的数据  可以是  堆上的数据  也可以是  栈上的数据    但是添加的时候略有区别 
     
	  添加 堆上的数据  call   push_data  
	  添加 栈上的数据  call   push_data_copy

   2. 添加进来的 堆上的数据  请勿手动释放 ！   ReadDataBuffer 会自动处理无用的内存  

*/
class ReadDataBuffer
{
public:
	ReadDataBuffer() {
		m_header = 0;
		m_offset = 0;
		m_size = 0;
	}
	/*
	push 数据时函数内部会进行一次拷贝 
	*/
	void push_data_copy(char * data, int size)
	{
		message m;
		m.buffer = new char[size];
		memcpy(m.buffer, data, size);
		m.size = size;
		m_mesage_list.push_back(m);
		this->m_size += size;
	}
	/*
	push 数据时 内部不进行拷贝  
	*/
	void push_data(char * data, int size)
	{
		message m;
		m.buffer = data;
		m.size = size;
		m_mesage_list.push_back(m);
		this->m_size += size;
	}

	void read_data(char *buffer, int size)
	{
		assert(m_size >= size);
		m_size -= size;
		while (true)
		{
			auto current = m_mesage_list.begin();
			int bsz = current->size - m_offset;
			if (bsz > size)
			{
				memcpy(buffer, current->buffer + m_offset, size);
				m_offset += size;
				return;
			}
			if (bsz == size)
			{
				memcpy(buffer, current->buffer + m_offset, size);
				m_offset = 0;
				//释放缓存区
				delete []current->buffer;
				m_mesage_list.pop_front();
				return;
			}
			else
			{
				memcpy(buffer, current->buffer + m_offset, bsz);
				m_offset = 0;
				buffer += bsz;
				size -= bsz;
				delete current->buffer;
				m_mesage_list.pop_front();
			}
		}
	}

	//返回 数据包的头部   即 数据的大小  
	//  -1   表示不能读取   
	int read_header(int header_size)
	{
		if (this->m_header == 0)
		{
			if (m_size < header_size)
			{
				return -1;
			}
			uint8_t plen[4];
			read_data((char*)plen, header_size);
			//
			if (header_size == 2)
			{
				m_header = Utility::big_to_ilittle_endian_16(plen);
			}
			else
			{
				m_header = Utility::big_to_ilittle_endian_32(plen);
			}

		}
		if (m_size < m_header)
		{
			return -1;    //不能读取  
		}

		return m_header;
	}

	//重置buffer
	void reset_databuffer() { m_header = 0; }
private:
	int m_header;
	int m_offset;
	int m_size;
	QList<message>  m_mesage_list;
};

class TcpNetWork : public QThread
{
	Q_OBJECT

public:
	TcpNetWork(QObject *parent = 0);
	~TcpNetWork();

	void startWork(const QString &hostName, quint16 port);
	void run() override;
	void sendData(uint16_t pkt_type ,char * data, uint16_t size_data);

signals:
	void ConnectServerFail(NetEventPacket);
	void recvData(NetEventPacket);


private:
	void recv_forward(int buffer_size);

private:
	QObject *		m_recver=nullptr;
	QString			m_host_name;
	quint16			m_port=0;
	QMutex			m_mutex;
	QWaitCondition	m_cond;
	bool			m_quit=0;
	OS_TcpSocket *	m_os_tcp=nullptr;
	QList<TcpPkt>	m_send_buff;
	QMutex			m_mutex_send_buff;
	ReadDataBuffer	m_read_data_buffer;
};